package com.hzncc.scaffold.core;

import com.hzncc.scaffold.exception.BusinessException;
import com.hzncc.scaffold.exception.RemoteException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Arrays;
import java.util.List;

/**
 * @author lqs
 * @date 2022/4/19
 */
@RestControllerAdvice(value = "cn.hzncc.machineassembly")
public class ResultTAdvice implements ResponseBodyAdvice<Object> {

  private static final Logger LOG = LoggerFactory.getLogger(ResultTAdvice.class);

  /**
   * 判断是否需要对响应机型处理,有需要自定义
   */
  @Override
  @SuppressWarnings("all")
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return true;
  }

  /**
   * 响应处理,controller是否使用ResultT包装类都可以
   */
  @Override
  @SuppressWarnings("all")
  public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                ServerHttpRequest request, ServerHttpResponse response) {
    //其实日志打印也可以在这里做
    if (body == null) {
      return ResultT.success();
    }
    //feign调用的直接返回
    if (body instanceof ResultT) {
      return body;
    }
    return ResultT.success(body);
  }

  //===============================以下是全局异常处理

  /**
   * 不合法的参数
   *
   * @param be
   * @return
   */
  //@ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler(IllegalArgumentException.class)
  public ResultT<Void> IllegalArgumentException(IllegalArgumentException be) {
    LOG.error("BusinessException:msg:{},stackTrace:{}", be.getMessage(), Arrays.toString(be.getStackTrace()));
    return ResultT.fail(be.getMessage(), ResponseEnum.CODE_9000.getCode());
  }

  /**
   * 远程调用异常
   *
   * @param be
   * @return
   */
  //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  @ExceptionHandler(RemoteException.class)
  public ResultT<Void> remoteException(RemoteException be) {
    LOG.error("RemoteException:msg:{},stackTrace:{}", be.msg, Arrays.toString(be.getStackTrace()));
    return ResultT.fail(be.msg, be.code);
  }

  /**
   * restTemplate异常处理
   *
   * @param be
   * @return
   */
  @ExceptionHandler(RestClientException.class)
  public ResultT<Void> restClientException(RestClientException be) {
    LOG.error("RestClientException: stackTrace:{}", Arrays.toString(be.getStackTrace()));
    return ResultT.fail("数据获取失败", ResponseEnum.CODE_9000.getCode());
  }

  /**
   * 处理业务异常
   *
   * @param be
   * @return
   */
  //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  @ExceptionHandler(BusinessException.class)
  public ResultT<Void> businessException(BusinessException be) {
    LOG.error("BusinessException:msg:{},stackTrace:{}", be.msg, Arrays.toString(be.getStackTrace()));
    return ResultT.fail(be.msg, be.code);
  }

  /**
   * 处理404异常
   *
   * @param be
   * @return
   */
  //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  @ExceptionHandler(NoHandlerFoundException.class)
  public ResultT<Void> noHandlerFoundException(Exception be) {
    return ResultT.fail("404 not found");
  }

  /**
   * 处理参数异常
   *
   * @param e
   * @return
   */
  //@ResponseStatus(HttpStatus.BAD_REQUEST)
  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResultT<Void> parameterExceptionHandler(MethodArgumentNotValidException e) {
    LOG.error("MethodArgumentNotValidException,{}", e.toString());
    // 获取异常信息
    BindingResult exceptions = e.getBindingResult();
    // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
    if (exceptions.hasErrors()) {
      List<ObjectError> errors = exceptions.getAllErrors();
      if (!errors.isEmpty()) {
        // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
        FieldError fieldError = (FieldError) errors.get(0);
        return ResultT.fail(fieldError.getDefaultMessage(), ResponseEnum.CODE_9000.getCode());
      }
    }
    return ResultT.fail(ResponseEnum.PARAM_ERROR);
  }

  @ExceptionHandler(Exception.class)
  public ResultT<Void> exception(Exception be) {
    LOG.error("Exception: msg:{}, stackTrace:{}", be.getMessage(), be.getStackTrace());
    return ResultT.fail(be.getMessage());
  }


}
